import threading
import time
import re
import os
import subprocess
import shlex

class FileSynchronizer(threading.Thread):
    def __init__(self, config):
        threading.Thread.__init__(self)
        self._delay = float(config.get('delay'))
        self._ignore = config.get('ignore')
        self._rsyncoptions = config.get('rsyncoptions')
        self._user = config.get('user')
        self._remotehost = config.get('remotehost')
        self._remotefolder = config.get('remotefolder')
        self._localfolder = config.get('localfolder').rstrip('/')
        self._timer_event = threading.Event()
        self._file_added_event = threading.Event()
        self._files_changed = {}
        self._file_added_during_timer = False
        self._lock = threading.Lock()
        self._files_to_sync = {}
        self._recursive = False
    
    def add_file(self, file, action):
        self._lock.acquire()
        if not self._recursive and not re.search(self._ignore, file):
            #Lazy dev mode: if tree change, rsync recursively from root, else file by file
            if action in (1, 4, 5):
                if os.path.exists(file) and os.path.isdir(file):#New folder
                    self._recursive = True
            elif action == 3:#Update
                if os.path.isdir(file):
                    self._files_changed[file + '/'] = (action, time.time())
                else:
                    parentfolder = os.path.dirname(file)
                    self._files_changed[parentfolder + '/'] = (action, time.time())
            elif action == 2 and os.path.dirname(file) == self._localfolder:
                self._files_changed[self._localfolder + '/'] = (action, time.time())
        self._file_added_during_timer = True
        self._timer_event.set()
        self._file_added_event.set()
        self._lock.release()

    def run(self):
        while 1:
            self._file_added_event.wait()
            while self._file_added_during_timer:
                self._lock.acquire()
                self._file_added_during_timer = False
                self._timer_event.clear()
                self._lock.release()
                self._timer_event.wait(self._delay)
            self._lock.acquire()
            self._files_to_sync = self._files_changed
            self._files_changed = {}
            self._file_added_event.clear()
            self._lock.release()
            self._synchronize()

    @staticmethod
    def _window_to_cygdrive(path):
        path = path.replace('\\', '/')
        path = re.sub('^([A-Z]):', '/cygdrive/\\1', path)
        return path

    def _synchronize(self):
        args = shlex.split(self._rsyncoptions)
        args.insert(0, 'rsync')
        localfolder = self._window_to_cygdrive(self._localfolder)
        dest = self._user + '@' + self._remotehost + ':' + self._remotefolder
        if self._recursive:
            args.append(localfolder + '/')
            args.insert(1, '-r')
            self._recursive = False
            args.append(dest)
            print ' '.join(args)
            subprocess.call(args)
        else: 
            args.insert(1, '-d')
            for file in self._files_to_sync: 
                tmpargs = args[:]
                cygfile = self._window_to_cygdrive(file)
                relpath = os.path.relpath(cygfile, localfolder)
                relpath = relpath.replace('\\', '/').replace(' ', '\ ')
                tmpargs.append(cygfile)
                tmpargs.append(dest + '/' + relpath)
                if os.path.exists(file):
                    print ' '.join(tmpargs)
                    subprocess.call(tmpargs)